#pragma once
#include<iostream>
#include<vector>
#include"MemUtil.h"
#include"ResourceManage.h"
#include"IO.h"
using namespace std;

class Block : public ResourceManage{
public:
    vector<Basic*> dataList;
    vector<Basic*> snapShot;
    vector<Record*> records;
    
    void clearData(){
        MemUtil::clearVecMem(dataList);
    }

    void clearSnapShot(){
        MemUtil::clearVecMem(snapShot);
    }
    
    void clearRecords(){
        MemUtil::clearVecMem(records);
    }

    void clear(){
        clearData();
        clearSnapShot();
        clearRecords();
    }

    void initData(char* fileData, const long& fileLen){
        clear();
        int dataSize = resourceInfo.getDataSize();
        TYPE dataType = resourceInfo.getDataType();
        for(int i = 0; i < fileLen; i += dataSize){
            dataList.push_back(BasicUtil::byteDataToBasicData(&fileData[i], dataType));
            snapShot.push_back(BasicUtil::byteDataToBasicData(&fileData[i], dataType));     //需要在初始化时初始化快照
        }
    }

    char* getDataBuffer(){
        int dataSize = resourceInfo.getDataSize();
        char* buffer = new char[dataList.size() * dataSize];
        int ind = 0;
        for(const auto it : dataList){
            memcpy(&buffer[ind], it->getByteData(), dataSize);
            ind += dataSize;
        }
        return buffer;
    }
    
    void batchWriteAddRecordsToMem(const int& blockSize, const vector<Basic*>& opDataVec){
        const string& baseName = resourceInfo.getBaseName();
        const string& tableName = resourceInfo.getTableName();
        const string& colName = resourceInfo.getColName();
        const int16_t& blockNo = resourceInfo.getBlockNo();
        for(size_t i = 0, opInd = blockSize; i < opDataVec.size(); i++){
            records.push_back(new Record(baseName, tableName, colName, blockNo, opInd++, ADD, nullptr, opDataVec[i]));
        }
    }
    
    //上方调用函数需保证三个vec大小相同，且modIndVec每一个下标合规。
    void batchWriteModRecordsToMem(const vector<int>& modIndVec, const vector<Basic*> oldDataVec, const vector<Basic*>& opDataVec){
        const string& baseName = resourceInfo.getBaseName();
        const string& tableName = resourceInfo.getTableName();
        const string& colName = resourceInfo.getColName();
        const int16_t& blockNo = resourceInfo.getBlockNo();
        for(size_t i = 0; i < modIndVec.size(); i++){
            records.push_back(new Record(baseName, tableName, colName, blockNo, modIndVec[i], MOD, oldDataVec[i], opDataVec[i]));
        }
    }

    void rollBackAccordRecord(const Record* rec){
        const OPTYPE& opType = rec->opType;
        const int& opInd = rec->opInd;
        Basic* oldData = dataList[opInd];      //获取回滚数据指针
        if(opType == ADD){
            dataList.erase(dataList.begin() + opInd);
        }
        else if(opType == MOD){
            dataList[opInd] = BasicUtil::getCopyBasicData(rec->oldData);
        }
        else{
            throw string("optype error");
        }
        MemUtil::clearPtrMem(oldData);      //就一个数据 就同步释放了
    }

    virtual void readFromDisk(){
        fstream f;
        if(!IOUtil::initFstreamIfExist(f, resourceInfo.getFullPath())){
            return;     //如果文件不存在 直接返回
        }
        const int64_t& fileLen = IOUtil::getFileLen(f);
        char* buffer = new char[fileLen];
        IOUtil::byteRead(buffer, f, fileLen);  //仅在读写磁盘阶段使全局IO串行
        f.close();                              //关闭文件描述符
        initData(buffer, fileLen);
        MemUtil::asyncClearPtrArrMem(buffer); //释放缓冲区
    }

    virtual void writeToDisk(){
        char* buffer = getDataBuffer();   //此阶段可以并行执行
        IOUtil::byteWrite(buffer, resourceInfo.getFullPath(), dataList.size() * resourceInfo.getDataSize());//仅在读写磁盘阶段使全局IO串行
        MemUtil::asyncClearPtrArrMem(buffer); //释放缓冲区
    }


    static void modBlockData(const Record* record, fstream& f, const int& dataSize){
        if(record->opType == DEL){
            throw string("Type error");
        }
        f.seekp(record->opInd * dataSize, ios_base::beg);
        f.write(record->newData->getByteData(), dataSize);
    }

    friend class ResourcePool; //需要从磁盘读数据
public:

    Block(const ResourceInfo& resInfo):ResourceManage(resInfo){
        if(resInfo.getDiskType() != BLOCK){
            throw string("diskType error");
        }
    }

    virtual ~Block(){
        clear();
    }

    Basic* getData(const size_t& loc){                            //为了保证性能，检验是否删除交由row来做
        return dataList[loc];
    }

    Basic* getSnapShotData(const size_t& loc){
        return snapShot[loc];
    }

    size_t getDataListSize() const {
        return dataList.size();
    }

    size_t getSnapShotSize() const {
        return snapShot.size();
    }



    void addData(const vector<Basic*>& opDataVec){ //添加数据
        batchWriteAddRecordsToMem(dataList.size(), opDataVec); //记录里的数据在外部拷贝创建， 在记录释放的时候一同释放。
        for(const Basic* opData : opDataVec){
            dataList.push_back(BasicUtil::getCopyBasicData(opData));
        }
    }


    void modData(const vector<int>& modIndVec, const vector<Basic*>& opDataVec){
        vector<Basic*> oldDataVec;
        for(const int& modInd : modIndVec){
            oldDataVec.push_back(dataList[modInd]);
        }
        batchWriteModRecordsToMem(modIndVec, oldDataVec, opDataVec);
        for(size_t i = 0; i < modIndVec.size(); i++){
            dataList[modIndVec[i]] = BasicUtil::getCopyBasicData(opDataVec[i]);
        }
    }

    virtual vector<Record*> getComitRecords(){
        makeSnapShot();
        vector<Record*> comitRecords = Record::getOptimizRecordVec(records, true);
        records.clear();
        return comitRecords;
    }

    virtual void memRollBack(){//也可以先优化记录再回滚 但都是在内存里的 其实没有必要
        for(int i = records.size() - 1; i >= 0; i--){
            rollBackAccordRecord(records[i]);
        }
        //由于回滚 record没有机会写进磁盘 需要马上清理
        MemUtil::asyncClearVecMem(records);
        //列表可能立马就要使用 同步清空 里面记录异步释放
        records.clear();
    }


    virtual void makeSnapShot(){
        getSnapShotLock(WRITE);    //防止修改的时候快照被读取
        for(Record* rec : records){
            const OPTYPE& opType = rec->opType;
            if(opType == ADD){
                snapShot.push_back(BasicUtil::getCopyBasicData(rec->newData));
            }
            else if(opType == MOD){
                snapShot[rec->opInd]->setData(rec->newData->getByteData());
            }
            else{
                throw string("opType error");
            }
        }
        releaseSnapShotLock();
    }


    //增量写入并释放record
    static void increWriteToDisk(const ResourceInfo& blockResInfo, const vector<Record*>& records){
        fstream f = IOUtil::getFstreamCreateIfNotExist(blockResInfo.getFullPath());
        const int32_t& dataSize = blockResInfo.getDataSize();
        for(const Record* rec : records){
            modBlockData(rec, f, dataSize);
        }
        f.close();
        //释放记录
        MemUtil::asyncClearVecMem(records);
    }
};
